
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;
using Swaf.Security;

namespace eCom
{
	class eComPricingBizRules : Syrinx.BaseBizRules
	{
		public IBizObjList getQuantityDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", companyId==null?ActiveCompanyId:companyId);
			IBizObjList pricing = app.appData.get("DA.eCom.GetCompanyQuantityDiscounts", m) as IBizObjList;
			return pricing;
		}

		public void deleteQuantityDiscount(IApplication app, IRuleContext context, Swaf.BGuid.Guid pricingId)
		{
			FlexiMap m = new FlexiMap();
			m.put("id", pricingId);
			app.appData.put("DA.eCom.DeleteCompanyQuantityDiscount", m);
		}

		public void updateQuantityDiscount(IApplication app, IRuleContext context, IBizObj pricing)
		{
			if (pricing.isNew)
			{
				pricing.put("companyId", ActiveCompanyId);
				app.appData.put("DA.eCom.AddCompanyQuantityDiscount", pricing);
			}
			else
				app.appData.put("DA.eCom.UpdateCompanyQuantityDiscount", pricing);
		}


		public IBizObjList getCodedDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", companyId == null ? ActiveCompanyId : companyId);
			IBizObjList pricing = app.appData.get("DA.eCom.GetCompanyCodedDiscounts", m) as IBizObjList;
			return pricing;
		}

		public void deleteCodedDiscount(IApplication app, IRuleContext context, Swaf.BGuid.Guid pricingId)
		{
			FlexiMap m = new FlexiMap();
			m.put("id", pricingId);
			app.appData.put("DA.eCom.DeleteCompanyCodedDiscount", m);
		}

		public void updateCodedDiscount(IApplication app, IRuleContext context, IBizObj pricing)
		{
			if (pricing.isNew)
			{
				pricing.put("companyId", ActiveCompanyId);
				app.appData.put("DA.eCom.AddCompanyCodedDiscount", pricing);
			}
			else
				app.appData.put("DA.eCom.UpdateCompanyCodedDiscount", pricing);
		}



		public IBizObjList getProductQuantityDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId)
		{
			FlexiMap m = new FlexiMap();
			m.put("productId", productId);
			IBizObjList pricings = app.appData.get("DA.eCom.GetProductQuantityDiscounts", m) as IBizObjList;
			return pricings;
		}

		public void setProductQuantityDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId, IBizObjList pricingsToRemove, IBizObjList pricingsToAdd)
		{
			try
			{
				if (productId != null)
				{
					FlexiMap m = new FlexiMap();
					m.put("productId", productId);
					if (pricingsToRemove != null)
						foreach (IBizObj pricing in pricingsToRemove)
						{
							m.put("pricingId", pricing.get("id"));
							app.appData.put("DA.eCom.DeleteProductQuantityDiscount", m);
						}
					if (pricingsToAdd != null)
						foreach (IBizObj pricing in pricingsToAdd)
						{
							m.put("pricingId", pricing.get("id"));
							app.appData.put("DA.eCom.AddProductQuantityDiscount", m);
						}
				}
			}
			catch (Exception e)
			{
				throw new eComException("Error executing setProductpricing.", e);
			}
		}


		public IBizObjList getProductCodedDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId)
		{
			FlexiMap m = new FlexiMap();
			m.put("productId", productId);
			IBizObjList pricings = app.appData.get("DA.eCom.GetProductCodedDiscounts", m) as IBizObjList;
			return pricings;
		}

		public void setProductCodedDiscounts(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId, IBizObjList pricingsToRemove, IBizObjList pricingsToAdd)
		{
			try
			{
				if (productId != null)
				{
					FlexiMap m = new FlexiMap();
					m.put("productId", productId);
					if (pricingsToRemove != null)
						foreach (IBizObj pricing in pricingsToRemove)
						{
							m.put("pricingId", pricing.get("id"));
							app.appData.put("DA.eCom.DeleteProductCodedDiscount", m);
						}
					if (pricingsToAdd != null)
						foreach (IBizObj pricing in pricingsToAdd)
						{
							m.put("pricingId", pricing.get("id"));
							app.appData.put("DA.eCom.AddProductCodedDiscount", m);
						}
				}
			}
			catch (Exception e)
			{
				throw new eComException("Error executing setProductCodedDiscounts.", e);
			}
		}

		public void updateSalesOrderCheckDiscounts(IApplication app, IRuleContext context, object resultValue, object[] inputParams)
		{
			IBizObj salesOrder = inputParams[2] as IBizObj;
			if (salesOrder != null)
				foreach (IBizObj orderItem in (IBizObjList)salesOrder.get("items"))
					checkOrderItemDiscounts(app, context, orderItem, salesOrder);
		}

		public IBizObj updateSalesOrderItemQuantityDiscounts(IApplication app, IRuleContext context, object resultValue, object[] inputParams)
		{
			IBizObj orderItem = resultValue as IBizObj;
			if (orderItem != null)
				checkOrderItemDiscounts(app, context, orderItem, null);

			return orderItem;
		}

		public void checkOrderItemDiscounts(IApplication app, IRuleContext context, IBizObj orderItem, IBizObj salesOrder)
		{
			bool orderItemUpdated = false;
			if (salesOrder == null)
			{
				IResults rc = context.RuleGroup.execute(context, "getCurrentSalesOrderDetails");
				salesOrder = rc.CallResults as IBizObj;
			}

			int orderItemQuantity = (int)orderItem.get("quantity");
			Decimal price = (Decimal)orderItem.get("product.sellPrice");
			IBizObjList pricings = context.RuleGroup.execute(context, "getProductQuantityDiscounts", orderItem.get("product.id")).CallResults as IBizObjList;
			if (pricings != null)
			{
				foreach (IBizObj pricing in pricings)
				{
					int pricingQuantity = (int)pricing.get("quantity");

					//Hack code - this should somehow be moved to reservation rule...
					//Need to get this drop to first client now, so we put it here for ease.
					if (salesOrder.containsField("reservation"))
					{
						orderItemQuantity = (int)salesOrder.get("reservation.numDaysStay");
						price = (Decimal)salesOrder.get("reservation.normalNightsTotal");
					}

					string bizRuleCalculator = (string)pricing.get("bizRuleCalculator");
					if (!Cmn.IsEmpty(bizRuleCalculator))
					{
						IResults rc = context.RuleGroup.execute(context, bizRuleCalculator, salesOrder, orderItem, pricing);

					}
					else if (orderItemQuantity >= pricingQuantity)
					{
						Decimal baseDiscount = (Decimal)pricing.get("baseDiscount");
						Decimal percentDiscount = (Decimal)pricing.get("percentCost");
						Decimal newPrice = price;
						newPrice -= baseDiscount;
						newPrice -= newPrice * (percentDiscount / 100);
						Decimal savings = (decimal)(price - newPrice);
						orderItem.put("price", price - savings);
						orderItemUpdated = true;
						//For now, I have commented out the adding up of descriptions because this is the only thing that is using it.
						//What happens if I leave in the original description is that the description for price discount builds up as
						//the user changes the quantity.

						//string desc = String.Format("{2}<br/>{0} applied for savings of {1}", pricing.get("name"), savings.ToString("N"), orderItem.get("description").ToString());
						string desc = String.Format("{0} applied for savings of {1}", pricing.get("name"), savings.ToString("N"));
						orderItem.put("description", desc);
						break;
					}
				}
			}

			if (!orderItemUpdated && !Cmn.IsEmpty(orderItem.get("description")))
			{
				//This is needed to clear out any existing savings description that could be in place.
				orderItem.put("description", "");
				orderItemUpdated = true;
			}


			if (!Cmn.IsEmpty(salesOrder.get("discountCode")) || salesOrder.isDirty("discountCode"))
			{
				orderItemUpdated = true;
				FlexiMap m = new FlexiMap();
				m["productId"] = orderItem.get("product.id");
				m["code"] = salesOrder.get("discountCode");
				IBizObj codedDiscount = app.appData.get("DA.eCom.GetProductCodedDiscountFromCode", m) as IBizObj;
				if (codedDiscount != null)
				{
					string bizRuleCalculator = (string)codedDiscount.get("bizRuleCalculator");
					if (!Cmn.IsEmpty(bizRuleCalculator))
					{
						IResults rc = context.RuleGroup.execute(context, bizRuleCalculator, salesOrder, orderItem, codedDiscount);
					}
					else
					{
						Decimal baseDiscount = (Decimal)codedDiscount.get("baseDiscount");
						Decimal percentDiscount = (Decimal)codedDiscount.get("percentCost");
						Decimal newPrice = price;
						newPrice -= baseDiscount;
						newPrice -= newPrice * (percentDiscount / 100);
						Decimal savings = (decimal)(price - newPrice);
						orderItem.put("price", newPrice);

						string desc = String.Format("{2}<br/>{0} applied for savings of {1}", codedDiscount.get("name"), ((decimal)savings * (int)orderItem.get("quantity")).ToString("N"), orderItem.get("description").ToString());
						orderItem.put("description", desc);
					}
				}
				else if(!orderItem.isDirty("price"))
					orderItem.put("price", price);
			}

			if (orderItemUpdated)
				app.appData.put("DA.eCom.UpdateSalesOrderItem", orderItem);
		}

	}
}
